﻿using Axiom.CodeManifold.Framework;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Xml.Serialization;

namespace Axiom.CodeManifold.WPF.ViewModels
{
	public class CodeManifoldViewModel : ViewModelBase
	{
		private ObservableCollection<ProjectCodeModel> _projects = new ObservableCollection<ProjectCodeModel>();

		private CodeModelViewModel _settings = new CodeModelViewModel();

		public Euclid Euclid { get; set; }

		public virtual bool IsConnected
		{
			get
			{
				return (Euclid.Ide != null && Euclid.Ide.Solution.IsOpen);
			}
		}

		public ObservableCollection<ProjectCodeModel> Projects
		{
			get { return _projects; }
		}

		public CodeModelViewModel Settings { get { return _settings; } }

		public string SolutionFullName
		{
			get
			{
				return Euclid.SolutionFullName;
			}
		}

		private EnvDTE.SolutionEvents SolutionEvents { get; set; }

		public CodeManifoldViewModel()
		{
			Euclid = Euclid.Instance;
			if (Euclid.IsHosted)
			{
				SetupEvents();
			}
			UpdateStatusInfo();

			if (true)
			{
				if (Euclid.IsReady)
				{
					Attach();
				}
			}
		}

		public async void AutoCommentAllFiles()
		{
			Status = "Commenting code";
			IsBusy = true;

			await Task.Run(() =>
				{
					try
					{
						Euclid.OpenUndo();
						Euclid.AutoCommentAllFiles();

						Status = "Successful";
					}
					catch (Exception ex)
					{
						Status = ex.Message.ReadLine();
					}
				});

			IsBusy = false;
		}

		public void AutoCommentMembers()
		{
			try
			{
				Euclid.AutoCommentDocument();
			}
			catch (Exception ex)
			{
				Status = ex.Message.ReadLine();
			}
		}

		public async void LaunchSolution()
		{
			if (IsBusy)
			{
				Status = "please wait...";
				return;
			}

			Attach();
			if (Euclid.IsReady)
			{
				Status = "Connected";
				return;
			}

			try
			{
				IsBusy = true;
				Euclid.LaunchSolutionInstances();
				Status = "Starting Visual Studio - polling";

				await Task.Run(() =>
				{
					int count = 0;
					while (!Euclid.IsReady)
					{
						count += 200;
						if ((count / 1000) > 120)
						{
							// wait for 2 minutes for visual studio to open
							break;
						}
						System.Threading.Thread.Sleep(200);
					}
				});
			}
			catch (Exception ex)
			{
				Status = new StringReader(ex.Message).ReadLine();
			}
			IsBusy = false;

			Attach();
			if (Euclid.IsReady)
			{
				Status = "Ready";
			}
			else
			{
				Status = "Can't connect to solution - try again";
			}
		}

		public void OnSolutionClosed()
		{
			UpdateStatusInfo();
		}

		public void OnSolutionOpened()
		{
			UpdateStatusInfo();
		}

		public async void RefreshModels()
		{
			IsBusy = true;
			try
			{
				IEnumerable<ProjectCodeModel> model = null;
				_projects.Clear();

				Status = "wait...";
				await Task.Run(() =>
				{					
					model = Euclid.GetProjects();
				});

				if (model != null)
				{
					foreach (var project in model)
					{
						_projects.Add(project);
					}
				}
				Status = "Ready";
			}
			catch (Exception ex)
			{
				Status = ex.Message.ReadLine();
			}
			IsBusy = false;
		}

		public void SortMembers()
		{
			try
			{
				Euclid.SortMembers();
			}
			catch (Exception ex)
			{
				Status = new StringReader(ex.Message).ReadLine();
			}
		}

		public void Undo()
		{
			Euclid.Undo();
		}

		private void Attach()
		{
			if (Euclid.Ide != null && !Euclid.Ide.Solution.IsOpen)
			{
				Euclid.Ide.Solution.Open(ReferenceData.SolutionFullName);
			}
			else
			{
				Euclid.Attach(ReferenceData.SolutionFullName);
			}
			RefreshModels();
			UpdateStatusInfo();
			SetupEvents();
		}

		private void SetupEvents()
		{
			if (Euclid.Ide == null || Euclid.Ide.Events == null)
			{
				Status = "WARNING: Can't setup solution events";
				return;
			}
			SolutionEvents = Euclid.Ide.Events.SolutionEvents;
			SolutionEvents.Opened += OnSolutionOpened;
			SolutionEvents.AfterClosing += OnSolutionClosed;
		}

		private void UpdateStatusInfo(string status = "Ready")
		{
			NotifyPropertyChanged("IsConnected");
			NotifyPropertyChanged("SolutionFullName");
			Status = status;
		}
	}
}
